/*
 * @Author: xiaosihan
 * @Date: 2022-08-20 14:50:15
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-10-05 10:14:30
 */
import { autorun } from 'mobx';
import {
  AmbientLight,
  BackSide,
  Color,
  DirectionalLight,
  FrontSide,
  MeshPhongMaterial,
  MeshStandardMaterial,
  SRGBColorSpace,
  Vector2,
  Vector3,
} from 'three';
import ThreeBase from 'three-base';
import MeshBase from 'three-base/MeshBase';
import threeUtils from 'three-base/threeUtils';
import editorStore from './editorStore';
import textureManager from './textureManager';
class Preview3DRenderer extends ThreeBase {
  constructor() {
    super();
    window.preview3DRenderer = this;
    this.setCameraType('orthographicCamera');
  }

  // 环境光
  ambientLight = (() => {
    const ambientLight = new AmbientLight('#fff', 1);
    this.scene.add(ambientLight);
    return ambientLight;
  })();

  // //点光源1
  // pointLight1 = (() => {
  //     const pointLight1 = new PointLight("#fff", 1);
  //     pointLight1.distance = 1000;
  //     pointLight1.decay = 0;
  //     pointLight1.position.set(10, 10, 10);
  //     this.scene.add(pointLight1);
  //     return pointLight1;
  // })();

  // // 方向光
  // directionalLight = (() => {
  //     const directionalLight = new DirectionalLight("#fff", 1);
  //     directionalLight.position.set(-10, 10, 5);
  //     directionalLight.target.position.set(0, 0, 0);
  //     directionalLight.castShadow = true;
  //     directionalLight.shadow.mapSize.set(1024, 1024);
  //     this.scene.add(directionalLight);
  //     return directionalLight;
  // })();

  // // 方向光2
  // directionalLight2 = (() => {
  //     const directionalLight = new DirectionalLight("#fff", 1);
  //     directionalLight.position.set(10, 10, -5);
  //     directionalLight.target.position.set(0, 0, 0);
  //     directionalLight.castShadow = true;
  //     directionalLight.shadow.mapSize.set(1024, 1024);
  //     this.scene.add(directionalLight);
  //     return directionalLight;
  // })();

  // 灯位1
  directionalLight1 = (() => {
    const directionalLight = new DirectionalLight('#fff', 0.6);
    directionalLight.position.set(0, 50, 0);
    directionalLight.target.position.set(0, 0, 0);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  // 灯位2
  directionalLight2 = (() => {
    const directionalLight = new DirectionalLight('#fff', 1);
    directionalLight.position.set(0, 0, -50);
    directionalLight.target.position.set(0, 0, 0);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  // 灯位3
  directionalLight3 = (() => {
    const directionalLight = new DirectionalLight('#fff', 0.47);
    directionalLight.position.set(-50, 0, 50);
    directionalLight.target.position.set(0, 0, 0);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  // 灯位4
  directionalLight4 = (() => {
    const directionalLight = new DirectionalLight('#fff', 0.45);
    directionalLight.position.set(-50, 0, -50);
    directionalLight.target.position.set(0, 0, 0);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  // 灯位5
  directionalLight5 = (() => {
    const directionalLight = new DirectionalLight('#fff', 1.8);
    directionalLight.position.set(50, 50, 50);
    directionalLight.target.position.set(0, 0, 0);
    this.scene.add(directionalLight);
    return directionalLight;
  })();

  //监听缝线的变化
  dispose2 = autorun(
    () => {
      const { design_data, needUpdateTime } = editorStore;
      const { threadColor } = design_data;
      if (needUpdateTime > 0) {
        this.front_cloth.traverseMesh((mesh) => {
          if (mesh.name.includes('thread')) {
            (mesh.material as MeshStandardMaterial).color = new Color(threadColor);
          }
        });
      }
    },
    { delay: 10 },
  );

  //纹理有更新时需要渲染
  dispose = autorun(
    () => {
      this.needRender = editorStore.needUpdateTime > 0;
    },
    { delay: 30 },
  );

  //设置尺寸
  setSize(width: number, height: number) {
    const { left, right, top, bottom } = this.orthographicCamera;
    super.setSize(width, height);
    Object.assign(this.orthographicCamera, { left, right, top, bottom });
  }

  init() {
    super.init();
    this.scene.background = new Color('#F5F5F5');
    this.gridHelper.visible = false;
    this.axesHelper.visible = false;
    // this.controls.enablePan = false;
    this.renderer.outputColorSpace = SRGBColorSpace;
    this.orthographicCamera.far = 5010;
    this.orthographicCamera.near = 4990;
    this.orthographicCamera.updateProjectionMatrix();
    this.autoRender = false;
    this.resetLookAt({
      center: new Vector3(0, 0, 0),
      position: new Vector3(0, 0, 7),
    });
  }

  //设置预览的canvas
  previewCanvas: Array<HTMLCanvasElement> = [];
  addPreviewCanvas(canvas: HTMLCanvasElement | null) {
    if (canvas) {
      let controlsConfig = {
        rotateSpeed: 0.5,
      };

      const pointerup = (e: PointerEvent) => {
        this.controls.rotateSpeed = controlsConfig.rotateSpeed;
        this.controls.zoomSpeed = controlsConfig.rotateSpeed * 4;
        const E = new PointerEvent('pointerup', e);
        document.removeEventListener('pointerup', pointerup);
        this.renderer.domElement.dispatchEvent(E);
      };

      canvas.addEventListener('pointermove', (e) => {
        const E = new PointerEvent('pointermove', e);
        this.renderer.domElement.dispatchEvent(E);
      });

      canvas.addEventListener('contextmenu', (e) => {
        const E = new PointerEvent('contextmenu', e);
        this.renderer.domElement.dispatchEvent(E);
      });

      canvas.addEventListener('pointerdown', (e) => {
        this.controls.rotateSpeed = controlsConfig.rotateSpeed * 4;
        const E = new PointerEvent('pointerdown', e);
        this.renderer.domElement.dispatchEvent(E);
        document.addEventListener('pointerup', pointerup);
      });

      canvas.addEventListener('pointercancel', (e) => {
        const E = new PointerEvent('pointercancel', e);
        this.renderer.domElement.dispatchEvent(E);
      });

      canvas.addEventListener(
        'wheel',
        (e) => {
          const E = new WheelEvent('wheel', e);
          this.renderer.domElement.dispatchEvent(E);
        },
        { passive: false },
      );

      // const ctx = canvas.getContext("2d");

      // if (ctx) {
      //     ctx.imageSmoothingQuality = "high";
      //     ctx.imageSmoothingEnabled = true;
      //     ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      //     ctx.drawImage(this.renderer.domElement, 0, 0, ctx.canvas.width, ctx.canvas.height);
      // }

      this.previewCanvas.push(canvas);
    }
  }

  // 加载衣服模型对象(正面)
  front_cloth = (() => {
    const front_cloth = new MeshBase();
    front_cloth.addEventListener('loaded', () => {
      threeUtils.scaleTo(front_cloth, 10, ['x', 'y']);
      threeUtils.center(front_cloth);
      const maps = textureManager.getAllTexture();
      front_cloth.traverseMesh((mesh) => {
        const { normalMap, transparent, opacity, alphaTest, map } =
          mesh.material as MeshPhongMaterial;
        mesh.material = new MeshStandardMaterial({
          normalMap,
          transparent,
          opacity,
          alphaTest,
          color: '#ffffff',
          metalness: 0,
          roughness: 0.8,
          side: FrontSide,
          map: maps[mesh.name] || map,
        });
      });
      this.needRender = true;
    });
    this.scene.add(front_cloth);
    return front_cloth;
  })();

  // 加载衣服模型对象(背面)
  back_cloth = (() => {
    const back_cloth = new MeshBase();
    back_cloth.addEventListener('loaded', () => {
      threeUtils.scaleTo(back_cloth, 10, ['x', 'y']);
      threeUtils.center(back_cloth);
      back_cloth.traverseMesh((mesh) => {
        const { normalMap, transparent, opacity, alphaTest, map } =
          mesh.material as MeshPhongMaterial;
        mesh.material = new MeshStandardMaterial({
          normalMap: normalMap,
          transparent: transparent,
          opacity: opacity,
          alphaTest: alphaTest,
          color: '#ffffff',
          metalness: 0,
          roughness: 0.8,
          side: BackSide,
          map: map,
        });
      });

      this.needRender = true;
    });
    this.scene.add(back_cloth);
    return back_cloth;
  })();

  // 设置内面的颜色
  setBackColor(color: `#${string}`) {
    this.back_cloth.traverseMesh((m) => {
      (m.material as MeshStandardMaterial).color.set(color);
    });
  }

  // 加载衣服
  async loadCloth(clothGLB: string) {
    // 清理预览canvas
    this.previewCanvas.map((canvas) => {
      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.imageSmoothingQuality = 'high';
        ctx.imageSmoothingEnabled = true;
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      }
    });

    await this.front_cloth.loadModel(clothGLB);
    await this.back_cloth.loadModel(clothGLB);

    const { activeComponent } = editorStore;
    editorStore.setActiveComponent('');
    await new Promise((resolve) => requestAnimationFrame(resolve));
    editorStore.setActiveComponent(activeComponent);

    // 更具模型大小调节相机的参数
    const frontSize = threeUtils.getSize(this.front_cloth);
    const sideLength = Math.max(frontSize.x, frontSize.y, frontSize.z);
    const rendererSize = this.renderer.getSize(new Vector2());
    this.setOrthographicCameraView(
      (rendererSize.x / Math.min(rendererSize.x, rendererSize.y)) * sideLength,
      (rendererSize.y / Math.min(rendererSize.x, rendererSize.y)) * sideLength,
    );
  }

  // 选中部位发生改变的时候, 切换视角
  dispose1 = autorun(
    async () => {
      const { activeComponent } = editorStore;
      await new Promise((resolve) => requestAnimationFrame(resolve));
      const { goodsData, loadding } = editorStore;
      const activeObject3d = this.front_cloth.getObjectByName(activeComponent);
      if (activeComponent && activeObject3d && goodsData && !loadding) {
        const size = threeUtils.getSize(activeObject3d);
        const center = threeUtils.getCenter(activeObject3d);
        const modelSize = size.length() * 1.4;
        const cameraDistance = modelSize / (2 * Math.tan((60 * Math.PI) / 360));
        const position = center.clone();

        const { cameraPosition } = goodsData?.component.find((c) => c.key === activeComponent)!;

        // 相机位置设置到 预设位置
        if (cameraPosition) {
          const { x, y, z } = cameraPosition;
          position.set(x, y, z);
        } else {
          position.x +=
            Math.sign(center.x) * (Math.abs(center.x) > Math.abs(center.z) ? cameraDistance : 0);
          position.z +=
            Math.sign(center.z + 0.5) *
            (Math.abs(center.z) > Math.abs(center.x) ? cameraDistance : 0);
        }

        this.setLookAt({ center, position });
      } else {
        this.resetLookAt({
          center: new Vector3(0, 0, 0),
          position: new Vector3(0, 0, 7),
        });
      }
    },
    { delay: 30 },
  );

  // 设置正交相机的视角哦
  setOrthographicCameraView(width: number, height: number) {
    this.orthographicCamera.left = width * -0.5 * 1.1;
    this.orthographicCamera.top = height * 0.5 * 1.1;
    this.orthographicCamera.right = width * 0.5 * 1.1;
    this.orthographicCamera.bottom = height * -0.5 * 1.1;
    // (this.camera as OrthographicCamera).updateProjectionMatrix();
  }

  // 清理画布和 模型
  clear() {
    this.renderer.clear();
    this.front_cloth.clear();
    this.back_cloth.clear();

    // 移除没有放在页面上的canvas
    this.previewCanvas = this.previewCanvas.filter((canvas) => threeUtils.inDocument(canvas));

    // 绘制到预览的canvas 上
    this.previewCanvas.map((canvas) => {
      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
      }
    });
  }

  render(): void {
    // this.pointLight1.position.copy(this.orthographicCamera.position);
    super.render();

    // 移除没有放在页面上的canvas
    this.previewCanvas = this.previewCanvas.filter((canvas) => threeUtils.inDocument(canvas));

    // 绘制到预览的canvas 上
    this.previewCanvas.map((canvas) => {
      const ctx = canvas.getContext('2d');
      if (ctx) {
        ctx.imageSmoothingQuality = 'high';
        ctx.imageSmoothingEnabled = true;
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        if (this.front_cloth.loaded && this.back_cloth.loaded) {
          ctx.drawImage(this.renderer.domElement, 0, 0, ctx.canvas.width, ctx.canvas.height);
        }
      }
    });
  }
}

const preview3DRenderer = new Preview3DRenderer();

export default preview3DRenderer;
